home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / gnu / gnulib / ohlutil / chmod.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-08-24  |  9.0 KB  |  367 lines

  1. /* chmod -- change permission modes of files
  2.    Copyright (C) 1989, 1990 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 1, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /*
  19.  * MS-DOS port (c) 1990 by Thorsten Ohl, td12@ddagsi3.bitnet
  20.  *
  21.  * To this port, the same copying conditions apply as to the
  22.  * original release.
  23.  *
  24.  * IMPORTANT:
  25.  * This file is not identical to the original GNU release!
  26.  * You should have received this code as patch to the official
  27.  * GNU release.
  28.  *
  29.  * MORE IMPORTANT:
  30.  * This port comes with ABSOLUTELY NO WARRANTY.
  31.  *
  32.  * $Header: e:/gnu/fileutil/RCS/chmod.c'v 1.3.0.2 90/06/29 00:46:32 tho Stable $
  33.  */
  34.  
  35. /* Usage: chmod [-Rcdfv] mode file...
  36.           mode is [ugoa...][[+-=][rwxXstugo...]...][,...] or octal number.
  37.  
  38.    Options:
  39.    -R    Recursively change modes of directory contents.
  40.    -c    Verbosely describe only files whose modes actually change.
  41.    -d    Dereference symbolic links (recursively change the modes of
  42.     directories pointed to by symbolic links).
  43.    -f    Do not print error messages about files.
  44.    -v    Verbosely describe changed modes.
  45.  
  46.    David MacKenzie <djm@ai.mit.edu> */
  47.  
  48. #include <stdio.h>
  49. #include <sys/types.h>
  50. #include "getopt.h"
  51. #include "modechange.h"
  52. #include "system.h"
  53.  
  54. #ifdef MSDOS
  55.  
  56. #include <malloc.h>
  57. #include <io.h>
  58.  
  59. extern void main (int argc, char **argv);
  60. extern void filemodestring (struct stat *,char *);
  61. extern void error (int status, int errnum, char *message, ...);
  62. extern void mode_string (unsigned short mode, char *str);
  63.  
  64. static int change_file_mode (char *file, struct mode_change *changes);
  65. static int change_dir_mode (char *dir, struct mode_change *changes,\
  66.                 struct stat *statp);
  67. extern char *savedir (char *dir, unsigned name_size);
  68. static char *stpcpy (char *dest, char *source);
  69. static void describe_change (char *file, unsigned short mode, int changed);
  70. static char *xmalloc (unsigned int n);
  71. static char *xrealloc (char *p, unsigned n);
  72. static char *stp_cpy (char *dest, char *source);
  73. static void usage (void);
  74.  
  75. #endif /* MSDOS */
  76.  
  77. #ifdef STDC_HEADERS
  78. #include <errno.h>
  79. #include <stdlib.h>
  80. #else
  81. char *malloc ();
  82. char *realloc ();
  83.  
  84. extern int errno;
  85. #endif
  86.  
  87. int lstat ();
  88. int stat ();
  89.  
  90. char *savedir ();
  91. char *xmalloc ();
  92. char *xrealloc ();
  93. int change_file_mode ();
  94. int change_dir_mode ();
  95. void describe_change ();
  96. void error ();
  97. void mode_string ();
  98. void usage ();
  99.  
  100. typedef enum
  101. {
  102.   false = 0, true = 1
  103. } boolean;
  104.  
  105. /* The name the program was run with. */
  106. char *program_name;
  107.  
  108. /* If true, change the modes of directories recursively. */
  109. boolean recurse;
  110.  
  111. /* If true, force silence (no error messages). */
  112. boolean force_silent;
  113.  
  114. /* If true, describe the modes we set. */
  115. boolean verbose;
  116.  
  117. /* If true, describe only modes that change. */
  118. boolean changes_only;
  119.  
  120. /* A pointer to either lstat or stat. */
  121. int (*xstat) ();
  122.  
  123. /* Parse the ASCII mode given on the command line into a linked list
  124.    of `struce mode_change' and apply that to each file argument. */
  125.  
  126. void
  127. main (argc, argv)
  128.      int argc;
  129.      char **argv;
  130. {
  131.   extern int optind;
  132.   struct mode_change *changes;
  133.   int errors = 0;
  134.   int modeind = 0;        /* Index of the mode argument in `argv'. */
  135.   int c;
  136.  
  137.   program_name = argv[0];
  138.   recurse = force_silent = verbose = changes_only = false;
  139. #ifdef MSDOS
  140.   strlwr (program_name);
  141. #else /* not MSDOS */
  142.   xstat = lstat;
  143. #endif /* not MSDOS */
  144.  
  145.  
  146.   while ((c = getopt (argc, argv, "RcdfvrwxXstugoa,+-=")) != EOF)
  147.     {
  148.       switch (c)
  149.     {
  150.     case 'r':
  151.     case 'w':
  152.     case 'x':
  153.     case 'X':
  154.     case 's':
  155.     case 't':
  156.     case 'u':
  157.     case 'g':
  158.     case 'o':
  159.     case 'a':
  160.     case ',':
  161.     case '+':
  162.     case '-':
  163.     case '=':
  164.       if (modeind != 0 && modeind != optind - 1)
  165.         error (1, 0, "invalid mode");
  166.       modeind = optind - 1;
  167.       break;
  168.     case 'R':
  169.       recurse = true;
  170.       break;
  171.     case 'c':
  172.       verbose = true;
  173.       changes_only = true;
  174.       break;
  175. #ifndef MSDOS
  176.     case 'd':
  177.       xstat = stat;
  178.       break;
  179. #endif /* MSDOS */
  180.     case 'f':
  181.       force_silent = true;
  182.       break;
  183.     case 'v':
  184.       verbose = true;
  185.       break;
  186.     default:
  187.       usage ();
  188.     }
  189.     }
  190.  
  191.   if (modeind == 0)
  192.     modeind = optind++;
  193.   if (optind >= argc)
  194.     usage ();
  195.  
  196.   changes = mode_compile (argv[modeind], MODE_MASK_EQUALS | MODE_MASK_PLUS);
  197.   if (changes == MODE_INVALID)
  198.     error (1, 0, "invalid mode");
  199.   else if (changes == MODE_MEMORY_EXHAUSTED)
  200.     error (1, 0, "virtual memory exhausted");
  201.  
  202.   for (; optind < argc; ++optind)
  203.     errors |= change_file_mode (argv[optind], changes);
  204.  
  205.   exit (errors);
  206. }
  207.  
  208. /* Change the mode of `file' according to the list of operations `changes'.
  209.    Return 0 if successful, 1 if errors occurred. */
  210.  
  211. int
  212. change_file_mode (file, changes)
  213.      char *file;
  214.      struct mode_change *changes;
  215. {
  216.   struct stat file_stats;
  217.   unsigned short newmode;
  218.   int errors = 0;
  219.  
  220. #ifdef MSDOS
  221.   strlwr (file);
  222.   if (stat (file, &file_stats))
  223. #else /* not MSDOS */
  224.   if ((*xstat) (file, &file_stats))
  225. #endif /* not MSDOS */
  226.     {
  227.       if (force_silent == false)
  228.     error (0, errno, "%s", file);
  229.       return 1;
  230.     }
  231. #ifdef S_IFLNK
  232.   if ((file_stats.st_mode & S_IFMT) == S_IFLNK)
  233.     return 0;
  234. #endif
  235.  
  236.   newmode = mode_adjust (file_stats.st_mode, changes);
  237.  
  238.   if (newmode != (file_stats.st_mode & 07777))
  239.     {
  240.       if (verbose)
  241.     describe_change (file, newmode, 1);
  242.       if (chmod (file, (int) newmode))
  243.     {
  244.       if (force_silent == false)
  245.         error (0, errno, "%s", file);
  246.       errors = 1;
  247.     }
  248.     }
  249.   else if (verbose && changes_only == false)
  250.     describe_change (file, newmode, 0);
  251.  
  252.   if (recurse && (file_stats.st_mode & S_IFMT) == S_IFDIR)
  253.     errors |= change_dir_mode (file, changes, &file_stats);
  254.   return errors;
  255. }
  256.  
  257. /* Recursively change the modes of the files in directory `dir'
  258.    according to the list of operations `changes'.
  259.    `statp' points to the results of lstat or stat on `dir'.
  260.    Return 0 if successful, 1 if errors occurred. */
  261.  
  262. int
  263. change_dir_mode (dir, changes, statp)
  264.      char *dir;
  265.      struct mode_change *changes;
  266.      struct stat *statp;
  267. {
  268.   char *name_space, *namep;
  269.   char *path;            /* Full path of each entry to process. */
  270.   unsigned dirlength;        /* Length of `dir' and '\0'. */
  271.   unsigned filelength;        /* Length of each pathname to process. */
  272.   unsigned pathlength;        /* Bytes allocated for `path'. */
  273.   int errors = 0;
  274.  
  275.   errno = 0;
  276.   name_space = savedir (dir, statp->st_size);
  277.   if (name_space == NULL)
  278.     {
  279.       if (errno)
  280.     {
  281.       if (force_silent == false)
  282.         error (0, errno, "%s", dir);
  283.       return 1;
  284.     }
  285.       else
  286.     error (1, 0, "virtual memory exhausted");
  287.     }
  288.  
  289.   dirlength = strlen (dir) + 1;    /* + 1 is for the trailing '/'. */
  290.   pathlength = dirlength + 1;
  291.   /* Give `path' a dummy value; it will be reallocated before first use. */
  292.   path = xmalloc (pathlength);
  293.   strcpy (path, dir);
  294.   path[dirlength - 1] = '/';
  295.  
  296.   for (namep = name_space; *namep; namep += filelength - dirlength)
  297.     {
  298.       filelength = dirlength + strlen (namep) + 1;
  299.       if (filelength > pathlength)
  300.     {
  301.       pathlength = filelength * 2;
  302.       path = xrealloc (path, pathlength);
  303.     }
  304.       strcpy (path + dirlength, namep);
  305.       errors |= change_file_mode (path, changes);
  306.     }
  307.   free (path);
  308.   free (name_space);
  309.   return errors;
  310. }
  311.  
  312. /* Tell the user the mode `mode' that file `file' has been set to;
  313.    if `changed' is zero, `file' had that mode already. */
  314.  
  315. void
  316. describe_change (file, mode, changed)
  317.      char *file;
  318.      unsigned short mode;
  319.      int changed;
  320. {
  321.   char perms[11];        /* "-rwxrwxrwx" ls-style modes. */
  322.  
  323.   mode_string (mode, perms);
  324.   perms[10] = '\0';        /* `mode_string' does not null terminate. */
  325.   if (changed)
  326.     printf ("mode of %s changed to %04o (%s)\n",
  327.         file, mode & 07777, &perms[1]);
  328.   else
  329.     printf ("mode of %s retained as %04o (%s)\n",
  330.         file, mode & 07777, &perms[1]);
  331. }
  332.  
  333. /* Allocate `n' bytes of memory dynamically, with error checking.  */
  334.  
  335. char *
  336. xmalloc (n)
  337.      unsigned n;
  338. {
  339.   char *p;
  340.  
  341.   p = malloc (n);
  342.   if (p == 0)
  343.     error (1, 0, "virtual memory exhausted");
  344.   return p;
  345. }
  346.  
  347. char *
  348. xrealloc (p, n)
  349.      char *p;
  350.      unsigned n;
  351. {
  352.   p = realloc (p, n);
  353.   if (p == 0)
  354.     error (1, 0, "virtual memory exhausted");
  355.   return p;
  356. }
  357.  
  358. void
  359. usage ()
  360. {
  361.   fprintf (stderr, "\
  362. Usage: %s [-Rcdfv] mode file...\n\
  363.        mode is [ugoa...][[+-=][rwxXstugo...]...][,...] or octal number\n",
  364.        program_name);
  365.   exit (1);
  366. }
  367.